package service

import (
	"encoding/binary"
	"encoding/json"
	"errors"
	"fmt"
	ClickHouse "gin/database"
	"gin/types"
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	"strconv"
	"time"
)

// GetInt64FromContext returns the value associated with the key as an integer.
func GetInt64FromContext(c *gin.Context, key string) (ui64 int64) {
	if val, ok := c.Get(key); ok && val != nil {
		ui64, _ = val.(int64)
	}
	return
}

// GetStringFromContext GetString returns the value associated with the key as a string.
func GetStringFromContext(c *gin.Context, key string) (res string) {
	if val, ok := c.Get(key); ok && val != nil {
		res, _ = val.(string)
	}
	return
}

// GetUserInfoFromContext  GetString returns the value associated with the key as a string.
func GetUserInfoFromContext(c *gin.Context, key string) (res types.UserInfoHeader) {
	if val, ok := c.Get(key); ok && val != nil {
		res, _ = val.(types.UserInfoHeader)
	}
	return
}

// Decimal 取小数
func Decimal(value float64) float64 {
	value, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", value), 64)
	return value
}

// GetBetweenDates 生成日期列表
func GetBetweenDates(sdate, edate string) []string {
	var d []string
	timeFormatTpl := "2006-01-02 15:04:05"
	if len(timeFormatTpl) != len(sdate) {
		timeFormatTpl = timeFormatTpl[0:len(sdate)]
	}
	date, err := time.ParseInLocation(timeFormatTpl, sdate, time.Local)
	if err != nil {
		// 时间解析，异常
		return d
	}
	date2, err := time.ParseInLocation(timeFormatTpl, edate, time.Local)
	if err != nil {
		// 时间解析，异常
		return d
	}
	if date2.Before(date) {
		// 如果结束时间小于开始时间，异常
		return d
	}
	// 输出日期格式固定
	timeFormatTpl = "2006-01-02"
	date2Str := date2.Format(timeFormatTpl)
	d = append(d, date.Format(timeFormatTpl))
	for {
		date = date.AddDate(0, 0, 1)
		dateStr := date.Format(timeFormatTpl)
		d = append(d, dateStr)
		if dateStr == date2Str {
			break
		}
	}
	return d
}

// IntVal 转换int64类型
func IntVal(value interface{}) (res int64) {
	if value == nil {
		return
	}
	switch value.(type) {
	case float64:
		ft := value.(float64)
		res = int64(ft)
	case float32:
		ft := value.(float32)
		res = int64(ft)
	case int:
		it := value.(int)
		res = int64(it)
	case uint:
		it := value.(uint)
		res = int64(it)
	case int8:
		it := value.(int8)
		res = int64(it)
	case uint8:
		it := value.(uint8)
		res = int64(it)
	case int16:
		it := value.(int16)
		res = int64(it)
	case uint16:
		it := value.(uint16)
		res = int64(it)
	case int32:
		it := value.(int32)
		res = int64(it)
	case uint32:
		it := value.(uint32)
		res = int64(it)
	case int64:
		res = value.(int64)
	case uint64:
		it := value.(uint64)
		res = int64(it)
	case string:
		res, _ = strconv.ParseInt(value.(string), 10, 64)
	case []byte:
		b := value.([]byte)
		res = int64(binary.BigEndian.Uint64(b))
	default:
	}
	return res
}

//func  MultipleArrayIntersect(array ...[]int){
//
//	ArrayIntersect(array[0],array[1])
//}
//

//func ArrayIntersect(A, B []int) (result []int) {
//	if len(A) < 1 || len(B) < 1 {
//		return
//	}
//
//	resMap := map[int]bool{}
//
//	for _, a := range A {
//		//去重
//		if _, ok := resMap[a]; ok {
//			continue
//		}
//
//		for _, b := range B {
//			if b == a {
//				result = append(result, a)
//				resMap[a] = true
//				break
//			}
//		}
//	}
//	return
//}

// ArrayCombine 取并集
func ArrayCombine(array [][]int64) (result []int64) {
	resMap := map[int64]bool{}

	for _, item := range array {
		for _, value := range item {
			//去重
			if _, ok := resMap[value]; !ok {
				result = append(result, value)
				resMap[value] = true
			}
		}
	}

	return
}

// CacheEnable 缓存是否开启
func CacheEnable() bool {
	return viper.GetString("server.cache") == "yes"
}

// GetCachedJson 缓存开启时读取
func GetCachedJson(rk string, res interface{}) (err error) {
	if viper.GetString("server.cache") != "yes" {
		err = errors.New("cache disabled")
		return
	}

	val, _ := ClickHouse.Rdb.Get(rk).Result()
	if val != "" {
		err = json.Unmarshal([]byte(val), &res)
		if err == nil {
			return
		}
	}
	err = errors.New("cache returns empty")
	return
}

// SetCacheJsonExpire 缓存开启时写入
func SetCacheJsonExpire(rk string, res interface{}, expire time.Duration) (err error) {
	if viper.GetString("server.cache") != "yes" {
		return
	}

	rs, err := json.Marshal(res)
	if err != nil {
		return
	}
	_, err = ClickHouse.Rdb.Set(rk, rs, expire).Result()
	return
}
